(function (window) {

    class MyPromise {
        /**
         * 定义 MyPromise 构造函数
         * @param {Function} executor 执行器函数
         */
        constructor(executor) {

            const self = this
            this.status = 'pending'     // promise 的状态
            this.data = undefined       // promise 的结果数据
            this.callbacks = []         // 存储回调函数，每个元素结构：{ onResolved() {}, onRejected() {} }

            function resolve(value) {
                if (self.status !== 'pending') return
                self.status = 'resolved'
                self.data = value
                if (self.callbacks.length) {    // 如果有待执行的 callback 函数，就异步执行回调函数 onResolved
                    setTimeout(() => {          // 放入队列中执行所有成功的回调
                        self.callbacks.forEach(callbackObj => {
                            callbackObj.onResolved(value)
                        })
                    })
                }
            }

            function reject(reason) {
                if (self.status !== 'pending') return
                self.status = 'rejected'
                self.data = reason
                if (self.callbacks.length) {    // 如果有待执行的 callback 函数，就异步执行回调函数 onRejected
                    setTimeout(() => {          // 放入队列中执行所有失败的回调
                        self.callbacks.forEach(callbackObj => {
                            callbackObj.onRejected(reason)
                        })
                    })
                }
            }

            try {
                executor(resolve, reject)
            } catch (err) {      // 如果执行器抛出异常，promise 对象就变成 rejected 状态
                reject(err)
            }

        }

        /**
         * 在原型对象上绑定 then 方法
         * @param {Function} onResolved 成功的回调
         * @param {Function} onRejected 失败的回调
         * @returns promise 对象
         */
        then(onResolved, onRejected) {
            const self = this

            onResolved = typeof onResolved === 'function' ? onResolved : value => value                 // 向后传递成功的 value
            // 指定默认的失败的回调（实现错误/异常传透的关键）
            onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }     // 向后传递失败的 reason

            return new MyPromise((resolve, reject) => {
                function handle(callback) {
                    try {
                        const result = callback(self.data)
                        if (result instanceof MyPromise) {      // 3. 如果回调返回 promise，return 的 promise 结果就是回调返回的 promise 结果
                            // result.then(value => resolve(value), reason => reject(reason))
                            result.then(resolve, reject)        // 上一行代码简写形式
                        } else {                                // 2. 如果回调返回的不是 promise，return 的 promise 就会成功，value 是回调返回的值
                            resolve(result)
                        }
                    } catch (error) {
                        reject(error)                           // 1. 如果回调抛出异常，return 失败的 promise，reason 就是 error
                    }
                }
                if (self.status === 'pending') {                    // 当前状态是 pending，保存回调函数
                    self.callbacks.push({
                        onResolved() {
                            handle(onResolved)
                        },
                        onRejected() {
                            handle(onRejected)
                        }
                    })
                } else if (self.status === 'resolved') {
                    setTimeout(() => {
                        handle(onResolved)
                    })
                } else if (self.status === 'rejected') {
                    setTimeout(() => {
                        handle(onRejected)
                    })
                }
            })
        }

        /**
         * 在原型对象上绑定 catch 方法
         * @param {Function} onRejected 失败的回调
         * @returns promise 对象
         */
        catch(onRejected) {
            return this.then(null, onRejected)
        }

        /**
         * 在函数对象上绑定 resolve 方法
         * @param {any} value 成功时的值
         * @returns 解析 value 后的 promise 对象
         */
        static resolve(value) {
            return new MyPromise((resolve, reject) => {
                if (value instanceof MyPromise) {
                    value.then(resolve, reject)
                } else {
                    resolve(value)
                }
            })
        }

        /**
         * 在函数对象上绑定 reject 方法
         * @param {any} reason 失败时的值
         * @returns 解析 reason 后的 promise 对象
         */
        static reject(reason) {
            return new MyPromise((resolve, reject) => {
                reject(reason)
            })
        }

        /**
         * 在函数对象上绑定 all 方法
         * @param {Array} promises 含有 promise 对象的数组
         * @returns 当所有 promise 都成功时，返回成功的 promise；只要有一个 promise 失败，返回失败的 promise
         */
        static all(promises) {
            const valueArr = new Array(promises.length)
            let resolvedCount = 0
            return new MyPromise((resolve, reject) => {
                promises.forEach((p, index) => {
                    MyPromise.resolve(p).then(value => {      // 如果 p 不是 promise，就用 resolve 方法把它变成 promise
                        resolvedCount += 1
                        valueArr[index] = value
                        if (resolvedCount === promises.length) {
                            resolve(valueArr)
                        }
                    }, reason => {
                        reject(reason)
                    })
                })
            })
        }

        /**
         * 在函数对象上绑定 race 方法
         * @param {Array} promises 含有 promise 对象的数组
         * @returns promise，其结果由第一个返回结果的 promise 的状态决定
         */
        static race(promises) {
            return new MyPromise((resolve, reject) => {
                promises.forEach((p, index) => {
                    MyPromise.resolve(p).then(value => {        // 如果 p 不是 promise，就用 resolve 方法把它变成 promise
                        resolve(value)
                    }, reason => {
                        reject(reason)
                    })
                })
            })
        }

        /**
         * 在函数对象上绑定 resolveDelay 方法
         * @param {any} value 成功时的值
         * @param {*} delay 延迟时间，单位：ms
         * @returns 解析 value 后的 promise 对象
         */
        static resolveDelay(value, delay) {
            return new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    if (value instanceof MyPromise) {
                        value.then(resolve, reject)
                    } else {
                        resolve(value)
                    }
                }, delay)
            })
        }

        /**
         * 在函数对象上绑定 rejectDelay 方法
         * @param {any} reason 失败时的值
         * @param {*} delay 延迟时间，单位：ms
         * @returns 解析 reason 后的 promise 对象
         */
        static rejectDelay(reason, delay) {
            return new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    reject(reason)
                }, delay)
            })
        }
    }

    window.MyPromise = MyPromise
})(window)